#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include "log.hpp"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
namespace MY
{
    using func_t = std::function<std::string(const std::string &)>;
    std::string defaultFunc(const std::string buffer){
        std::string result = "CLIENT:"+buffer; 
        return result;
    }
    const int defaultsockfd = -1;
    class udpServer
    {
    private:
        int _sockfd;
        // std::string _ip;
        uint16_t _port;
        bool isrunning = false;
        func_t _func;
    public:
        udpServer(uint16_t port,func_t func = defaultFunc):_sockfd(defaultsockfd),_port(port),_func(func){}
        void init() {
            _sockfd = socket(AF_INET,SOCK_DGRAM,0);
            if(_sockfd < 0){
                LOG(logLevel::FATAL)<<"socket error";
                exit(1);
            } 
            LOG(logLevel::INFO)<<"socket success ,sockfd:"<<_sockfd;
            //填充sockaddr
            struct sockaddr_in local;
            bzero(&local,sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);
            // if(inet_aton(_ip.c_str(),&local.sin_addr) != 1){
            //     LOG(logLevel::FATAL)<<"inet_aton fail";
            //     exit(1);
            // }
            local.sin_addr.s_addr = INADDR_ANY;
            //绑定端口号
            if(bind(_sockfd,(const sockaddr*)&local,sizeof(local)) != 0){
                LOG(logLevel::FATAL)<<"bind fail";
                exit(1);
            }
            LOG(logLevel::INFO)<<"bind success ,sockfd:"<<_sockfd;
            LOG(logLevel::INFO)<<"udpServer init successfully!!";
        }
        void start()
        {
            isrunning = true;
            LOG(logLevel::INFO)<<"udpServer start";
            while(isrunning){
                const int bufferSize = 1024;
                char buffer[bufferSize] = {0};
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);

                int s =recvfrom(_sockfd,buffer,bufferSize - 1,0,(sockaddr*)&peer,&len);
                if(s > 0){
                    buffer[s] = 0;
                    char clientBuffer[bufferSize];
                    std::string clientIp;
                    if(inet_ntop(AF_INET,&peer.sin_addr,clientBuffer,bufferSize) != nullptr){
                        clientIp = clientBuffer;
                    }
                    else{
                        LOG(logLevel::ERROR)<<"CAN`T GET THE IP OF CLIENT!!";
                    }
                    std::string reply = "CLIENT["+ clientIp+"]:"+buffer; 
                    // std::string reply = _func("CLIENT["+ clientIp+"]:"+buffer)
                    LOG(logLevel::DEBUG)<<reply;
                    sendto(_sockfd,reply.c_str(),reply.size(),0,(sockaddr*)&peer,sizeof(peer));
                }
                else{
                    LOG(logLevel::ERROR)<<"recvfrom error";
                }
            }
            LOG(logLevel::INFO)<<"udpServer exit";
        }
        ~udpServer()
        {
            close(_sockfd);
        }
    };

}